from penguin import desk, auto, logging
from penguin.window import Window
from uiautomation import ListControl, ButtonControl

class OffcialAccountsArticleEntry:
    """
    此类实例表示公众号文章入口，也就是公众号文章列表窗口列表中的任意一项，可以通过点击它打开文章详情窗格。
    """

    def __init__(self, title:str, updateTime:str, button:ButtonControl):
        """
        初始化公众号文章入口类型。

        参数：
            title 文章标题。
            updateTime 文章更新时间。 
            button 文章入口按钮。
        """
        self.title = title
        self.updateTime = updateTime
        self.button = button

class OfficialAccountArticle(Window):
    """
    此类型实例表示一个公众号文章详情窗格。
    """

    def __init__(self, name:str, class_name:str, parent):
        """
        初始化窗口实例。

        参数：
            name 窗口名称。
            className 窗口类名。
            parent 父级控件。
        """
        
        super().__init__(name, '文章窗口', class_name, parent)
        self.window = desk.PaneControl(searchDepth = 1, ClassName = self.class_name)

    def get_body(self)-> str:
        """
        获取此窗格中文章内容。

        返回：
            如果此公众号文章详情窗格在桌面，返回文章内容，否则返回None。
        """
        if self.is_on_desk():
            # 如果此公众号文章详情窗格在桌面，使用热键组合方式复制并返回文章内容。
            self.window.Click(x=20, y=100)
            auto.SendKeys('{Ctrl}(A)')
            auto.SendKeys('{Ctrl}(C)')
            logging.info('获取以 %s 为标题 公众号 文章内容。' % self.name)
            return auto.GetClipboardHtml()
        return None
    
    def get_title(self)-> str:
        """
        获取此窗格中文章标题。

        返回：
            如果此公众号文章详情窗格在桌面，返回文章标题，否则返回None。
        """
        if self.is_on_desk():
            logging.info('获取以 %s 为标题 公众号 文章标题。' % self.name)
            return self.name
        return None
    
    def get_url(self)-> str:
        """
        获取此窗格中文章URL。

        返回：
            如果此公众号文章详情窗格在桌面，返回文章URL，否则返回None。
        """
        if self.is_on_desk():
            try:
                self.window.GetChildren()[3].Control(searchDepth=4, Name='更多').Click(waitTime=2)
                self.window.GetChildren()[0].Control(searchDepth=5, Name='复制链接').Click(waitTime=1)
                logging.info('获取以 %s 为标题 公众号 文章链接地址。' % self.name)
                return auto.GetClipboardText()
            except LookupError as e:
                if e.args[0].find('更多') >= 0:
                    logging.error('查找不到 更多 元素，微信界面结构是否修改。')
                if e.args[0].find('复制链接') >= 0:
                    logging.error('查找不到 复制链接 元素，微信界面结构是否修改。')
        return None
    
class OfficialAccount(Window):
    """
    此类实例表示一个公众号文章列表窗口。
    """

    def __init__(self, name:str, class_name:str, parent):
        """
        初始化窗口实例。

        参数：
            name 窗口名称。
            className 窗口类名。
            parent 父级控件。
        """
        super().__init__(name, '公众号窗口', class_name, parent)
        self.entries:dict[str, OffcialAccountsArticleEntry] = {} 

    def __disassemble_items(self, items: list[ListControl])->list[str]:
        """
        拆解列表项中的控件为公众号文章入口类型实例。返回公众号文章列表中的所有文章标题。

        参数：
            items 列表项控件。
        返回：
            文章标题。
        """
        updateTime = ''
        for item in items:
            # 此时列表项控件为文章更新时间。
            if not item.Name == '':
                updateTime = item.Name
                continue
            # 此时列表项控件为文章入口按钮及文章标题等。
            else:
                 # 依据控件结构获得文章标题父级控件。
                controls = item.GetChildren()[0].GetChildren()[0].GetChildren()[1].GetChildren()
                for control in controls:
                    # 如果文章标题父级控件无子控件，说明不包含文章控件。
                    if len(control.GetChildren()) > 0: 
                        button = control.ButtonControl(searchDepth=3)
                        self.entries[button.Name] = OffcialAccountsArticleEntry(button.Name, updateTime, button)
        return list(self.entries.keys())

    def get_title_list(self)-> list[str]:
        """
        获取此公众号文章列表窗口中所有的文章标题集合。

        返回：
            返回文章标题集合。
        """
        if self.is_on_desk():
            try:
                items = self.window.ListControl(searchDepth=10, Name='消息')
                logging.info('获取 %s 公众号窗口 中文章标题集合。' % self.name)
                return self.__disassemble_items(items.GetChildren())
            except Exception as e:
                logging.error('在获取 %s 公众号窗口 中文章标题集合时出错 %s 。' % (self.name, e.args[0]))
                return None
        return None
    
    def find_entrance(self, name):
        return self.entries[name].button
    
    def open_article(self, name:str)-> OfficialAccountArticle:
        """
        打开由文章标题指定的公众号文章详情窗格。

        参数：
            name 文章标题。
        返回：
            如果成功返回公众号文章详情窗格，否则返回None。
        """
        return self.open_new_window(name, 'Chrome_WidgetWin_0', OfficialAccountArticle)
        